/// Refly License
/// 
/// Copyright (c) 2004 Jonathan de Halleux, http://www.dotnetwiki.org
///
/// This software is provided 'as-is', without any express or implied warranty. 
/// In no event will the authors be held liable for any damages arising from 
/// the use of this software.
/// 
/// Permission is granted to anyone to use this software for any purpose, 
/// including commercial applications, and to alter it and redistribute it 
/// freely, subject to the following restrictions:
///
/// 1. The origin of this software must not be misrepresented; 
/// you must not claim that you wrote the original software. 
/// If you use this software in a product, an acknowledgment in the product 
/// documentation would be appreciated but is not required.
/// 
/// 2. Altered source versions must be plainly marked as such, 
/// and must not be misrepresented as being the original software.
///
///3. This notice may not be removed or altered from any source distribution.

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using System.Collections;
using System.ComponentModel;

namespace Refly.CodeDom
{
	/// <summary>
	/// A class that controls the generation of code.
	/// </summary>
	public class CodeGenerator
	{
		private string copyright = "Generated by Refly";
		private string tab = "    ";
        private string mainNamespace = "";
        private CodeDomProvider provider = new CSharpCodeProvider();
		private CodeGeneratorOptions options = new CodeGeneratorOptions();
		private bool createFolders=true;

		public CodeGenerator()
		{
			this.Options.BracingStyle="C";
		}

        [Category("Data")]
        public string MainNamespace
        {
            get
            {
                return this.mainNamespace;
            }
            set
            {
                this.mainNamespace = value;
            }
        }

        [Category("Data")]
		public string Tab
		{
			get
			{
				return this.tab;
			}
			set
			{
				this.tab = value;
			}
		}
		
		[Category("Data")]
		public string Copyright
		{
			get
			{
				return this.copyright;
			}
			set
			{
				this.copyright=value;
			}
		}

		[Category("Data")]
		public bool CreateFolders
		{
			get
			{
				return this.createFolders;
			}
			set
			{
				this.createFolders=value;
			}
		}

        [Browsable(false)]
		public CodeDomProvider Provider
		{
			get
			{
				return this.provider;
			}
			set
			{
				if (value==null)
					throw new ArgumentNullException("provider");
				this.provider = value;
			}
		}

		[Category("Data")]
		public CodeGeneratorOptions Options
		{
			get
			{
				return this.options;
			}
		}

		public static CodeDomProvider CsProvider
		{
			get
			{
				return new CSharpCodeProvider();
			}
		}

		public static CodeDomProvider VbProvider
		{
			get
			{
				return new VBCodeProvider();
			}
		}

        public event StringEventHandler FileCreated;

        protected virtual void OnFileCreated(StringEventArgs args)
        {
            if (this.FileCreated != null)
                this.FileCreated(this, args);
        }

        private string PathFromNamespace(string outputPath, string ns)
		{
            string path = null;
            if (ns.StartsWith(this.MainNamespace))
            {
                string nsNormalized = ns.Substring(this.MainNamespace.Length);
                path = Path.Combine(outputPath, this.MainNamespace);
                path = Path.Combine(path, nsNormalized.Replace('.', '\\'));
            }
            else
            {
                path = Path.Combine(outputPath, ns.Replace('.', '\\'));
            }
            Directory.CreateDirectory(path);
			return path;
		}

		public void GenerateCode(
            string outputPath, 
            NamespaceDeclaration ns
            )
		{	
			if (ns==null)
				throw new ArgumentNullException("ns");

            ICodeGenerator gen = provider.CreateGenerator();
            foreach(DictionaryEntry de in ns.ToCodeDom()) 
			{
				FileName key = (FileName)de.Key;
				CodeNamespace nms = (CodeNamespace)de.Value;

				// creating directory
				string path; 
				if (createFolders)
					path = PathFromNamespace(outputPath,key.Namespace);
				else
					path = outputPath;

                string filePath = Path.Combine(path,key.Name + "." + this.Provider.FileExtension);

                using(StreamWriter writer = new StreamWriter(filePath))
				{
					// add copyright
					nms.Comments.Add(new CodeCommentStatement(copyright));

					// Create a TextWriter to a StreamWriter to an output file.
					IndentedTextWriter tw = new IndentedTextWriter(writer,this.tab);
					// Generate source code using the code generator.
                    gen.GenerateCodeFromNamespace(nms, tw, options);

                    // log
                    this.OnFileCreated(new StringEventArgs(filePath));
                }
			}
		}
	}
}
